import { Injectable, HttpException, HttpStatus } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { Role } from '../entities/role.entity'
import { Permission } from '../entities/permission.entity'
import { UserRole } from '../entities/user-role.entity'
import { CreateRoleDto } from '../dto/create-role.dto'
import { UpdateRoleDto } from '../dto/update-role.dto'
import { CreatePermissionDto } from '../dto/create-permission.dto'
import { UpdatePermissionDto } from '../dto/update-permission.dto'
import { In } from 'typeorm'
import { PermissionTree } from 'src/common/interfaces/rbac.interface'

/**
 * RBAC服务
 * 提供角色、权限、用户角色关联的业务逻辑
 */
@Injectable()
export class RbacService {
  constructor(
    @InjectRepository(Role)
    private readonly roleRepo: Repository<Role>,
    @InjectRepository(Permission)
    private readonly permissionRepo: Repository<Permission>,
    @InjectRepository(UserRole)
    private readonly userRoleRepo: Repository<UserRole>,
  ) {}

  // ==================== 角色管理 ====================

  /**
   * 创建角色
   * @param createRoleDto 创建角色数据
   */
  async createRole(createRoleDto: CreateRoleDto): Promise<Role> {
    // 检查角色名是否已存在
    const existRole = await this.roleRepo.findOne({
      where: { name: createRoleDto.name },
    })
    if (existRole) {
      throw new HttpException('角色名已存在', HttpStatus.BAD_REQUEST)
    }

    // 创建角色
    const role = this.roleRepo.create(createRoleDto)
    const savedRole = await this.roleRepo.save(role)

    // 分配权限
    if (createRoleDto.permissionIds && createRoleDto.permissionIds.length > 0) {
      await this.assignPermissionsToRole(savedRole.id, createRoleDto.permissionIds)
    }

    return this.findRoleById(savedRole.id)
  }

  /**
   * 获取所有角色列表
   * @param page 页码
   * @param limit 每页数量
   */
  async findAllRoles(page: number = 1, limit: number = 10): Promise<{ data: Role[]; total: number }> {
    const [data, total] = await this.roleRepo.findAndCount({
      relations: ['permissions'],
      skip: (page - 1) * limit,
      take: limit,
      order: { sort: 'ASC', createdAt: 'DESC' },
    })

    return { data, total }
  }

  /**
   * 根据ID获取角色详情
   * @param id 角色ID
   */
  async findRoleById(id: number): Promise<Role> {
    const role = await this.roleRepo.findOne({
      where: { id },
      relations: ['permissions'],
    })
    if (!role) {
      throw new HttpException('角色不存在', HttpStatus.NOT_FOUND)
    }
    return role
  }

  async removeRolesFromUser(userId: number, roleIds: number[]): Promise<void> {
    await this.userRoleRepo.delete({
      userId,
      roleId: In(roleIds),
    })
  }

  /**
   * 更新角色信息
   * @param id 角色ID
   * @param updateRoleDto 更新数据
   */
  async updateRole(id: number, updateRoleDto: UpdateRoleDto): Promise<Role> {
    const role = await this.findRoleById(id)

    // 如果更新角色名，检查是否重复
    if (updateRoleDto.name && updateRoleDto.name !== role.name) {
      const existRole = await this.roleRepo.findOne({
        where: { name: updateRoleDto.name },
      })
      if (existRole) {
        throw new HttpException('角色名已存在', HttpStatus.BAD_REQUEST)
      }
    }

    // 更新角色信息
    Object.assign(role, updateRoleDto)
    await this.roleRepo.save(role)

    // 更新权限
    if (updateRoleDto.permissionIds) {
      await this.assignPermissionsToRole(id, updateRoleDto.permissionIds)
    }

    return this.findRoleById(id)
  }

  /**
   * 删除角色
   * @param id 角色ID
   */
  async removeRole(id: number): Promise<void> {
    const role = await this.findRoleById(id)
    await this.roleRepo.remove(role)
  }

  /**
   * 为角色分配权限
   * @param roleId 角色ID
   * @param permissionIds 权限ID列表
   */
  async assignPermissionsToRole(roleId: number, permissionIds: number[]): Promise<void> {
    const role = await this.findRoleById(roleId)
    const permissions = await this.permissionRepo.findByIds(permissionIds)
    role.permissions = permissions
    await this.roleRepo.save(role)
  }

  // ==================== 权限管理 ====================

  /**
   * 创建权限
   * @param createPermissionDto 创建权限数据
   */
  async createPermission(createPermissionDto: CreatePermissionDto): Promise<Permission> {
    // 检查权限名是否已存在
    const existPermission = await this.permissionRepo.findOne({
      where: { permission: createPermissionDto.permission },
    })
    if (existPermission) {
      throw new HttpException('权限名已存在', HttpStatus.BAD_REQUEST)
    }

    // 创建权限
    const permission = this.permissionRepo.create(createPermissionDto)
    return this.permissionRepo.save(permission)
  }

  /**
   * 获取权限列表
   * @param page 页码
   * @param limit 每页数量
   */
  async findPermissions(page: number = 1, limit: number = 10): Promise<{ data: Permission[]; total: number }> {
    const [data, total] = await this.permissionRepo.findAndCount({
      skip: (page - 1) * limit,
      take: limit,
      order: { sort: 'ASC', createdAt: 'DESC' },
    })

    return { data: this.buildPermissionTree(data), total }
  }

  /**
   * 获取所有权限列表
   */
  async findAllPermissions(): Promise<Permission[]> {
    return this.permissionRepo.find()
  }

  /**
   * 根据ID获取权限详情
   * @param id 权限ID
   */
  async findPermissionById(id: number): Promise<Permission> {
    const permission = await this.permissionRepo.findOne({ where: { id } })
    if (!permission) {
      throw new HttpException('权限不存在', HttpStatus.NOT_FOUND)
    }
    return permission
  }

  /**
   * 更新权限信息
   * @param id 权限ID
   * @param updatePermissionDto 更新数据
   */
  async updatePermission(id: number, updatePermissionDto: UpdatePermissionDto): Promise<Permission> {
    const permissionRow = await this.findPermissionById(id)

    // 如果更新权限名，检查是否重复
    if (updatePermissionDto.permission && updatePermissionDto.permission !== permissionRow.permission) {
      const existPermission = await this.permissionRepo.findOne({
        where: { permission: updatePermissionDto.permission },
      })
      if (existPermission) {
        throw new HttpException('权限名已存在', HttpStatus.BAD_REQUEST)
      }
    }

    // 更新权限信息
    Object.assign(permissionRow, updatePermissionDto)
    return this.permissionRepo.save(permissionRow)
  }

  /**
   * 删除权限
   * @param id 权限ID
   */
  async removePermission(id: number): Promise<void> {
    const permission = await this.findPermissionById(id)
    await this.permissionRepo.remove(permission)
  }

  // ==================== 用户角色管理 ====================

  /**
   * 为用户分配角色
   * @param userId 用户ID
   * @param roleIds 角色ID列表
   */
  async assignRolesToUser(userId: number, roleIds: number[]): Promise<void> {
    // 先删除用户现有角色
    await this.removeAllRolesFromUser(userId)

    if (roleIds && roleIds.length > 0) {
      const userRoles = roleIds.map((roleId) =>
        this.userRoleRepo.create({
          userId,
          roleId,
        }),
      )
      await this.userRoleRepo.save(userRoles)
    }
  }

  /**
   * 为用户分配角色（通过角色名）
   * @param userId 用户ID
   * @param roleNames 角色名列表
   */
  async assignRolesToUserByRoleNames(userId: number, roleNames: string[]): Promise<void> {
    const roles = await this.roleRepo.find({ where: { name: In(roleNames) } })
    const roleIds = roles.map((role) => role.id)
    await this.assignRolesToUser(userId, roleIds)
  }

  /**
   * 移除用户的所有角色
   * @param userId 用户ID
   */
  async removeAllRolesFromUser(userId: number): Promise<void> {
    await this.userRoleRepo.delete({ userId })
  }

  /**
   * 获取用户的所有角色
   * @param userId 用户ID
   */
  async getUserRoles(userId: number): Promise<Role[]> {
    const userRoles = await this.userRoleRepo.find({
      where: { userId },
      relations: ['role'],
    })
    return userRoles.map((ur) => ur.role)
  }

  /**
   * 获取用户的所有权限（树形结构）
   * @param userId 用户ID
   */
  async findUserPermissions(userId: number): Promise<PermissionTree[]> {
    const isSuperAdmin = await this.isSuperAdmin(userId)
    const permissions = new Set<Permission>()
    if (isSuperAdmin) {
      const allPermissions = await this.findAllPermissions()
      allPermissions.forEach((permission) => {
        permissions.add(permission)
      })
    } else {
      const userRoles = await this.userRoleRepo.find({
        where: { userId },
        relations: ['role', 'role.permissions'],
      })
      userRoles.forEach((ur) => {
        if (ur.role.permissions) {
          ur.role.permissions.forEach((permission) => {
            permissions.add(permission)
          })
        }
      })
    }
    // 转换为树形结构
    return this.buildPermissionTree(Array.from(permissions))
  }

  /**
   * 将权限列表构建为树形结构
   * @param permissions 权限列表
   * @param parentId 父权限ID，默认为null（顶级权限）
   */
  private buildPermissionTree(permissions: Permission[], parentId: number | null = null): Permission[] {
    return permissions
      .filter((permission) => permission.parentId === parentId)
      .map((p) => ({
        ...p,
        children: this.buildPermissionTree(permissions, p.id),
      }))
  }

  /**
   * 检查用户是否有指定权限
   * @param userId 用户ID
   * @param permissionName 权限名称
   */
  async hasPermission(userId: number, permissionName: string): Promise<boolean> {
    const permissions = await this.findUserPermissions(userId)
    // 从树形结构中查找权限
    const checkPermission = (permissions: PermissionTree[], name: string): boolean => {
      for (const p of permissions) {
        if (p.permission === name) {
          return true
        }
        if (p.children && p.children.length > 0) {
          if (checkPermission(p.children, name)) {
            return true
          }
        }
      }
      return false
    }
    return checkPermission(permissions, permissionName)
  }

  /**
   * 检查用户是否有指定角色
   * @param userId 用户ID
   * @param roleName 角色名称
   */
  async hasRole(userId: number, roleName: string): Promise<boolean> {
    const roles = await this.getUserRoles(userId)
    return roles.some((r) => r.name === roleName)
  }

  /**
   * 检查用户是否为超级管理员
   * @param userId 用户ID
   */
  async isSuperAdmin(userId: number): Promise<boolean> {
    return this.hasRole(userId, 'super_admin')
  }
}
